//
// Created by linxi on 2021/1/22.
//
#include "myMQTT.h"

extern PubSubClient mqttClient;

// 连接MQTT服务器并订阅信息
void connectMQTTServer() {
    // 根据ESP8266的MAC地址生成客户端ID（避免与其它ESP8266的客户端ID重名）
    String clientId = Device_Name;

    // 以“-Will”结尾，这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
    String willString = Device_Name + "-Will";
    char willTopic[willString.length() + 1];
    strcpy(willTopic, willString.c_str());

    /* 连接MQTT服务器
    boolean connect(const char* id, const char* user,
                    const char* pass, const char* willTopic,
                    uint8_t willQos, boolean willRetain,
                    const char* willMessage, boolean cleanSession);
    若让设备在离线时仍然能够让qos1工作，则connect时的cleanSession需要设置为false
                    */
    String willMsgString = Device_Name + willMsg;
    char willMSG[willMsgString.length() + 1];
    strcpy(willMSG, willMsgString.c_str());

    if (mqttClient.connect(clientId.c_str(), mqtt_username, mqtt_password, willTopic, willQoS, willRetain, willMSG)) {
        Serial.println("MQTT Server Connected.");
        Serial.print("Server Address: ");
        Serial.println(mqttServer);
        Serial.print("ClientId: ");
        Serial.println(clientId);
        Serial.print("Will Topic: ");
        Serial.println(willTopic);
        publishOnlineStatus();     //发布在线状态
        subscribeTopic(LED_CONTROL);

    } else {
        Serial.print("MQTT Server Connect Failed. Client State:");
        Serial.println(mqttClient.state());
        delay(5000);
    }
}

// 发布信息
void pubMQTTmsg(const String &topic, const char *publishMsg, bool status) {

    // 这么做是为确保不同用户进行MQTT信息发布时，ESP8266客户端名称各不相同，
    String topicString = Device_Name + Pub_pefix + topic;
    char publishTopic[topicString.length() + 1];
    strcpy(publishTopic, topicString.c_str());

    // 实现ESP8266向主题发布信息
    if (mqttClient.publish(publishTopic, publishMsg, status)) {
        Serial.println("Publish Topic:");
        Serial.println(publishTopic);
        Serial.println("Publish message:");
        Serial.println(publishMsg);
    } else {
        Serial.println("Message Publish Failed.");
    }
}

// 订阅指定主题
void subscribeTopic(const String &topic) {
    // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时，所订阅的主题名称不同
    String topicString = Device_Name + Sub_pefix + topic;
    char subTopic[topicString.length() + 1];
    strcpy(subTopic, topicString.c_str());

    // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
    // 请注意subscribe函数第二个参数数字为QoS级别。这里为QoS = 1
    if (mqttClient.subscribe(subTopic, 0)) {
        Serial.print("Subscribed Topic: ");
        Serial.println(subTopic);
    } else {
        Serial.print("Subscribe Fail...");
    }
}

// 发布信息
void publishOnlineStatus() {
    // 以“-Will”结尾，这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
    String willString = Device_Name + "-Will";
    char willTopic[willString.length() + 1];
    strcpy(willTopic, willString.c_str());

    // 建立设备在线的消息。此信息将以保留形式向遗嘱主题发布
    String onlineMessageString = Device_Name + "-1";
    char onlineMsg[onlineMessageString.length() + 1];
    strcpy(onlineMsg, onlineMessageString.c_str());

    // 向遗嘱主题发布设备在线消息
    if (mqttClient.publish(willTopic, onlineMsg, true)) {
        Serial.print("Published Online Message: ");
        Serial.println(onlineMsg);
    } else {
        Serial.println("Online Message Publish Failed.");
    }
}